package com.shuimin.as.service.sys;

import com.shuimin.as.AccessDeniedException;
import com.shuimin.as.App;
import com.shuimin.as.model.sys.Rank;
import com.shuimin.as.model.sys.Shop;
import pond.common.S;
import pond.common.STRING;
import pond.db.JDBCTmpl;
import pond.db.Record;
import pond.db.sql.*;

import java.util.List;

import static pond.common.f.Tuple.pair;

public class RankService {

  public static List<Rank> all() {
    SqlSelect select = Sql.select("*").from(Rank.class);
    Shop shop = App.currentUser().shop();
    if (shop == null || shop.type() == Shop.TYPE_NORMAL) {
      select.where("type", Criterion.EQ, String.valueOf(Rank.TYPE_NORMAL));
    }
    return App.DB.get(t -> t.query(Rank.class, select));
  }

  public static SqlUpdate setRankType(String rank_id, int type) {
    S._assertNotNull(rank_id);
    if (App.currentRoles().hasAny(SysRoles.Roles.RANK_MGMT.id)) {
      SqlUpdate update = Sql.update(Rank.class)
          .set(pair("type", type))
          .where("id", rank_id);
      return update;
    }
    throw new AccessDeniedException(SysRoles.Roles.RANK_MGMT.id);
  }

  public static Rank get(String id) {

    return App.DB.get(t -> t.recordById(Rank.class, id));
  }

  public static Rank getByName(String name, JDBCTmpl t) {
    List<Rank> list = t.recordsQuery(Rank.class, "name", Criterion.EQ, name);
    if (list.size() > 0) return list.get(0);
    else return null;
  }

  public static void add(JDBCTmpl t, Rank rank) {
    S._assert(t);
    if (App.currentRoles().hasAny(SysRoles.Roles.RANK_MGMT.id)) {
      t.recordInsert(rank);
    } else throw new AccessDeniedException();
  }

  public static void del(JDBCTmpl t, String id) {

    S._assertNotNull(t, id);
    if (App.currentRoles().hasAny(SysRoles.Roles.RANK_MGMT.id)) {
      t.recordExists(Rank.class, id);
      t.recordDelete(Record.newValue(Rank.class).setId(id));
    } else throw new AccessDeniedException();
  }

  public static void update(JDBCTmpl t, Rank rank) {
    S._assertNotNull(t, rank, rank.id());
    if (App.currentRoles().hasAny(SysRoles.Roles.RANK_MGMT.id)) {
      t.recordUpdate(rank);
    } else throw new AccessDeniedException();
  }

  public static List<Record> rolesForRank(JDBCTmpl t, String rank_id) {
    SqlSelect select = Sql.select("role_id", "rolename")
        .from("v_rank_has_role")
        .where("id", Criterion.EQ, rank_id);

    return t.query(select.tuple());
  }

  public static void addRoleToRank(JDBCTmpl t, String role_id, String rank_id) {

    SqlInsert insert = Sql.insert().into("r_rank_has_role").values(pair("rank_id", rank_id), pair("role_id", role_id));
    if (App.currentRoles().hasAny(SysRoles.Roles.RANK_MGMT.id)) {
      t.exec(insert);
      //查询所有由此岗位的用户
      List<Record> users = t.query("SELECT * FROM r_user_rank WHERE rank_id = ?", rank_id);
      //更新他们的权限
      S._for(users).each(user -> syncRanksForUser(t, user.get("user_id")));
    } else throw new AccessDeniedException();
  }

  public static void removeRoleFromRank(JDBCTmpl t, String role_id, String rank_id) {

    SqlDelete delete = Sql.delete().from("r_rank_has_role")
        .where("role_id", Criterion.EQ, role_id)
        .where("rank_id", Criterion.EQ, rank_id);
    if (App.currentRoles().hasAny(SysRoles.Roles.RANK_MGMT.id)) {
      t.exec(delete);
      //查询所有由此岗位的用户
      List<Record> users = t.query("SELECT * FROM r_user_rank WHERE rank_id = ?", rank_id);
      //更新他们的权限
      S._for(users).each(user -> syncRanksForUser(t, user.get("user_id")));
    } else throw new AccessDeniedException();
  }

  /**
   * 通过用户查询出所属岗位
   *
   * @param user_id
   * @return
   */
  public static List<Rank> ranksForUser(JDBCTmpl t, String user_id) {
    S._assertNotNull(t, user_id);
    return t.query(Rank.class,
                   "SELECT t_rank.* FROM t_rank " +
                       "LEFT JOIN r_user_rank " +
                       "ON t_rank.id=r_user_rank.rank_id " +
                       "WHERE r_user_rank.user_id = ?",
                   user_id);
  }

  /**
   * 为用户添加岗位
   *
   * @param rank
   * @param user
   */
  public static void addRankToUser(JDBCTmpl t, String rank, String user) {
    S._assertNotNull(t, rank, user);
    if (App.currentRoles().hasAny(SysRoles.Roles.HR_USER_PRIVILEGE.id)) {
      t.exec("INSERT r_user_rank VALUES(?,?)", user, rank);
      syncRanksForUser(t, user);
    } else throw new AccessDeniedException();
  }

  /**
   * 为用户删除岗位
   *
   * @param rank
   * @param user
   */
  public static void removeRankFromUser(JDBCTmpl t, String rank, String user) {
    S._assertNotNull(t, rank, user);
    if (App.currentRoles().hasAny(SysRoles.Roles.HR_USER_PRIVILEGE.id)) {
      t.exec("DELETE FROM r_user_rank WHERE user_id = ? and rank_id = ?", user, rank);
      syncRanksForUser(t, user);
    } else throw new AccessDeniedException();
  }

  public static void syncRanksForUser(JDBCTmpl t, String user_id) {
    S._assertNotNull(t, user_id);
    List<Record> all_roles = S.array();

    S._for(ranksForUser(t, user_id)).each(rank -> {
      S._for(rolesForRank(t, rank.id())).each(role -> {
        if (!S._for(all_roles).some(al -> al.get("role_id") != null && al.get("role_id").equals(role.get("role_id"))))
          all_roles.add(role);
      });
    });

    //delete all current roles
    App.rbac.user_role_del(user_id, t);
    //add new
    S._for(all_roles).filter(role -> STRING.notBlank((String) role.get("role_id")))
        .each(r -> App.rbac.user_add_role(user_id, r.get("role_id"), t));
  }

}
